package api

import (
	"bridge_viewing/db"
	"bridge_viewing/dto"
	"bridge_viewing/enum"
	"bridge_viewing/model"
	"bridge_viewing/utils"
	"github.com/pkg/errors"
	"gorm.io/gorm"
	"strings"
	"time"
)

type SceneRoomReq struct {
	dto.BaseReqParam
	Id int `json:"id"` //场景id
}

type SceneQuestionReq struct {
	dto.BaseReqParam
	RoomId int `json:"room_id"`
}

type SceneQuestionResp struct {
	QuestionId      int      `json:"question_id"`
	RoomId          int      `json:"room_id"`          // 场景id
	Title           string   `json:"title"`            // 问题标题
	QuestionOptions []string `json:"question_options"` // 问题选项
	Score           int      `json:"score"`            // 问题分数
}

type UserQuestionReq struct {
	dto.BaseReqParam
	UserAnswerDTO
}

type UserAnswerDTO struct {
	QuestionId int    `json:"question_id"`
	UserAnswer string `json:"user_answer"`
}

type UserQuestionResp struct {
	IsCorrect  bool   `json:"is_correct"`
	TotalScore int    `json:"total_score"`
	AwardCode  string `json:"award_code"`
}

type UserScoreInfoResp struct {
	TotalScore int    `json:"total_score"`
	AwardCode  string `json:"award_code"`
	IsReceived int    `json:"is_received"`
}

type CheckUserQuestionReq struct {
	dto.BaseReqParam
	QuestionIds []int `json:"question_ids"`
}

type CheckUserQuestionResp struct {
	QuestionId int  `json:"question_id"`
	IsAllowed  bool `json:"is_allowed"`
}

// ListSceneApi @Description: 场景列表
func ListSceneApi(req *dto.BaseReqParam) (*dto.CommonRespParam, *enum.ErrorObj) {
	var arr []model.Scene
	db.DBGClient.Find(&arr)
	return &dto.CommonRespParam{
		Data: arr,
	}, nil
}

// ListSceneRoomApi @Description: 场景房间列表
func ListSceneRoomApi(req *SceneRoomReq) (*dto.CommonRespParam, *enum.ErrorObj) {
	var arr []model.SceneRoom
	db.DBGClient.Where(model.SceneRoom{SceneId: req.Id}).Find(&arr)
	return &dto.CommonRespParam{
		Data: arr,
	}, nil
}

// ListRoomQuestionApi @Description: 获取房间的题目列表
func ListRoomQuestionApi(req *SceneQuestionReq) (*dto.CommonRespParam, *enum.ErrorObj) {
	var arr []model.SceneRoomQuestion
	db.DBGClient.Where(model.SceneRoomQuestion{RoomId: req.RoomId}).Find(&arr)
	var resp []SceneQuestionResp
	for _, q := range arr {
		sq := SceneQuestionResp{
			QuestionId:      q.ID,
			RoomId:          q.RoomId,
			Title:           q.Title,
			QuestionOptions: strings.Split(q.QuestionOptions, ","),
			Score:           q.Score,
		}
		resp = append(resp, sq)
	}
	return &dto.CommonRespParam{
		Data: resp,
	}, nil
}

// CheckUserQuestionApi @Description: 检查用户题目答题情况，是否允许作答
func CheckUserQuestionApi(req *CheckUserQuestionReq) (*dto.CommonRespParam, *enum.ErrorObj) {
	var userQuestionArr []CheckUserQuestionResp
	for _, id := range req.QuestionIds {
		checkResp := CheckUserQuestionResp{
			QuestionId: id,
			IsAllowed:  true,
		}
		var userQuestion model.UserQuestion
		result := db.DBGClient.Where(model.UserQuestion{
			UserId:     req.UserId,
			QuestionId: id,
		}).First(&userQuestion)
		if result.Error == nil {
			if userQuestion.IsCorrect == 1 {
				checkResp.IsAllowed = false
			} else {
				if !checkUserCanSubmitQuestion(&userQuestion) {
					checkResp.IsAllowed = false
				}
			}
		}
		userQuestionArr = append(userQuestionArr, checkResp)
	}
	return &dto.CommonRespParam{
		Data: userQuestionArr,
	}, nil
}

// SubmitUserQuestionApi @Description: 提交用户答题记录
func SubmitUserQuestionApi(req *UserQuestionReq) (*dto.CommonRespParam, *enum.ErrorObj) {
	var todayUserQuestion model.UserQuestion
	hasUserAnswer := false
	err := db.DBGClient.Where(model.UserQuestion{UserId: req.UserId, QuestionId: req.QuestionId}).First(&todayUserQuestion).Error
	if err == nil {
		hasUserAnswer = true
		if !checkUserCanSubmitQuestion(&todayUserQuestion) {
			return nil, enum.RepeatSubmitAnswerErr
		}
	}
	isCorrect := false
	answerCorrect := 0
	currentTotalScore := 0
	var roomQuestion model.SceneRoomQuestion
	db.DBGClient.First(&roomQuestion, req.QuestionId)
	if req.UserAnswer == roomQuestion.QuestionAnswer {
		isCorrect = true
		answerCorrect = 1
		currentTotalScore = roomQuestion.Score
	}
	if hasUserAnswer {
		if todayUserQuestion.IsCorrect == 0 && isCorrect {
			db.DBGClient.Model(&model.UserQuestion{}).Where(model.UserQuestion{
				UserId:     req.UserId,
				QuestionId: req.QuestionId,
			}).Updates(&model.UserQuestion{
				UserAnswer: req.UserAnswer,
				IsCorrect:  answerCorrect,
			})
		}
	} else {
		uq := model.UserQuestion{
			UserId:          req.UserId,
			QuestionId:      req.QuestionId,
			RoomId:          roomQuestion.RoomId,
			Title:           roomQuestion.Title,
			QuestionOptions: roomQuestion.QuestionOptions,
			QuestionAnswer:  roomQuestion.QuestionAnswer,
			Score:           roomQuestion.Score,
			UserAnswer:      req.UserAnswer,
			IsCorrect:       answerCorrect,
		}
		db.DBGClient.Create(&uq)
	}
	resp := UserQuestionResp{
		IsCorrect: isCorrect,
	}
	if isCorrect {
		awardCode := ""
		var userScore model.UserScore
		result := db.DBGClient.Where(model.UserScore{UserId: req.UserId}).First(&userScore)
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			userScoreObj := model.UserScore{
				UserId:     req.UserId,
				TotalScore: currentTotalScore,
				AwardCode:  awardCode,
				IsReceived: 0,
			}
			db.DBGClient.Create(&userScoreObj)
			resp.TotalScore = currentTotalScore
		} else {
			total := userScore.TotalScore + currentTotalScore
			resp.TotalScore = total
			if total >= 100 {
				awardCode = utils.RandStringRunes(6)
				resp.AwardCode = awardCode
			}
			db.DBGClient.Model(&model.UserScore{}).Where(model.UserScore{UserId: req.UserId}).Updates(&model.UserScore{
				TotalScore: total,
				AwardCode:  awardCode,
			})
		}
	}
	return &dto.CommonRespParam{
		Data: resp,
	}, nil
}

// FetchUserScoreApi @Description: 获取用户的分数及兑奖码
func FetchUserScoreApi(req *dto.BaseReqParam) (*dto.CommonRespParam, *enum.ErrorObj) {
	var userScore model.UserScore
	db.DBGClient.Where(model.UserScore{UserId: req.UserId}).First(&userScore)
	resp := UserScoreInfoResp{
		TotalScore: userScore.TotalScore,
		AwardCode:  userScore.AwardCode,
		IsReceived: userScore.IsReceived,
	}
	return &dto.CommonRespParam{
		Data: resp,
	}, nil
}

func checkUserCanSubmitQuestion(userQuestion *model.UserQuestion) bool {
	nowTime := time.Now()
	if userQuestion.IsCorrect == 1 {
		return false
	}
	if userQuestion.UpdatedAt.AddDate(0, 0, 1).After(nowTime) {
		if userQuestion.UpdatedAt.Day() == nowTime.Day() {
			return false
		}
	}
	return true
}
